
#include <stdio.h>
#include <stdarg.h>

#include "peerloger.h"
#include "simulator.h"
#include "config.h"

PeerLoger* PeerLoger::instance_ = NULL;

PeerLoger::PeerLoger()
    : file_(NULL)
	, file_name_counter_(0)
{
    instance_ = this;

	file_name_[0] = '\0';

    log_sch_ = config.loger_.sch;
	log_trans_ = config.loger_.trans;
	log_error_ = config.loger_.error;
    log_debug_ = config.loger_.debug;
	log_result_ = config.loger_.result;
	log_chord_  = config.loger_.chord;
    
    to_screen_ = config.loger_.toscreen;
    auto_flush_ = config.loger_.flush;

}

PeerLoger::~PeerLoger()
{
	fprintf(stderr, "max logfile counter:%d\n", file_name_counter_-1);
    if (file_)
    {
        fclose(file_);
        file_ = NULL;
    }

    assert(instance_);
    instance_ = NULL;
}

bool PeerLoger::init()
{

	strncpy(base_file_name_, config.loger_.file_name.c_str(), PEERLOGER_MAX_FILE_NAME_LEN); 
	nextFileName();
	file_ = fopen(file_name_,"w");
	if (NULL==file_){
		fprintf(stderr, "Can not open log file: %s\n",file_name_);
		return false;
	}
	return true;
}

void PeerLoger::destroy()
{
	if ( instance_!=NULL ){
		RELEASE_OBJ( instance_ );
	}
}

bool PeerLoger::create()
{
	NEW_OBJECT( PeerLoger, instance_, () );
	return true;
}

PeerLoger& PeerLoger::instance()
{
    assert(instance_);//loger should be created by tcl scripts
    return (*instance_);
}

void PeerLoger::flush()
{
    if (file_){
        fflush(file_);
    }
}

void PeerLoger::logScheduler(int level, const char* fmt, ...)
{
    if (!log_sch_) return;
    va_list v;
    va_start(v, fmt);
    log("sch",fmt,v);
    va_end(v);
}

void PeerLoger::logTrans(int level, const char* fmt, ...)
{
	if (!log_trans_) return;
    va_list v;
    va_start(v, fmt);
    log("trans",fmt,v);
    va_end(v);
}

void PeerLoger::logDebug(int level, const char* fmt, ...)
{
    if (!log_debug_) return;
    va_list v;
    va_start(v, fmt);
    log("debug",fmt,v);
    va_end(v);
}

void PeerLoger::logError(int level, const char* fmt, ...)
{
    if (!log_error_) return;
    va_list v;
    va_start(v, fmt);
    log("error",fmt,v);
    va_end(v);
}

void PeerLoger::logResult(int level, const char* fmt, ...)
{
	if (!log_result_) return;
	va_list v;
	va_start(v, fmt);
	log("result",fmt,v);
	va_end(v);
}

void PeerLoger::logChord(int level, const char* fmt, ...)
{
	if (!log_chord_) return;
	va_list v;
	va_start(v, fmt);
	log("chord",fmt,v);
	va_end(v);
}

void PeerLoger::log( const char* type, const char* fmt, va_list va)
{
#define BUFFSIZE_ 4096
    char strbuf[BUFFSIZE_];
#ifdef WIN32
	sprintf( strbuf, "type:%s time:%f\t", type, Simulator::instance().clock());
    int offset = (int)strlen(strbuf);
    char *str = strbuf + offset;
    vsprintf(str, fmt, va);
#else
    snprintf( strbuf, BUFFSIZE_, "type:%s time:%f\t", type, Simulator::instance().clock());
    int offset = (int)strlen(strbuf);
    char *str = strbuf + offset;
    vsnprintf(str, BUFFSIZE_-offset-1, fmt, va);//reserve one byte for '\n'
#endif
    strcat(str, "\n");

    if (to_screen_) fputs(strbuf,stderr);
    if(file_){
		if (ensureFileSize()){
			fprintf(file_,strbuf);
			if (auto_flush_){
				fflush(file_);
			}
		} else{
			fputs("PeerLoger::log ensureFileSize failed", stderr);
		}
    }

#undef BUFFSIZE_
}

bool PeerLoger::ensureFileSize()
{
	//in 32 bit operating system, max file size is 2GB
	//so when the log file grows to 1GB, a new file will 
	//be created
#define MAX_LOG_FILE_SIZE 1073741824
	//assuming we are at the end of file
	long end_pos = ftell(file_);
	if (end_pos<0) return false;

	if (end_pos<MAX_LOG_FILE_SIZE) return true;
	nextFileName();
	fclose(file_);
	file_ = fopen(file_name_,"w");

	if (file_==NULL){
		fprintf(stderr, "PeerLoger::ensureFileSize can not open file %s\n", file_name_);
		return false;
	}

	fprintf(stderr, "log file created, name:%s\n", file_name_);
	return true;

#undef MAX_LOG_FILE_SIZE
}

void PeerLoger::nextFileName()
{
#ifdef WIN32
	sprintf(file_name_, "logs//%s%d", base_file_name_, file_name_counter_);
#else
	snprintf(file_name_, PEERLOGER_MAX_FILE_NAME_LEN, "logs//%s%d", base_file_name_, file_name_counter_);
#endif
	file_name_counter_++;
}
